﻿// Inner Fire 游戏引擎库
// PhysicsWorld - 物理世界
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层（4）
// 用于统一管理世界。我在想，我是不是要一个这样多余的东西。是否可以将其合并到Objects的管理中？
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-06-17

#pragma once

#include <EASTL/vector.h>
#include <game/physics/constraint.h>
#include <graphics/graphics_def.h>
#include <static_string.h>
#include <game/physics/collider.h>

namespace ifire::game {
class Scene;
class RigidBody;

class PhysicsWorld {
public:
  PhysicsWorld(Scene& scene, ikit::sstr name);
  PhysicsWorld(const PhysicsWorld& lhs) = delete;
  PhysicsWorld& operator=(const PhysicsWorld& lhs) = delete;
  ~PhysicsWorld();

  // 更新项目
  void FixedUpdate(float delta_time);
  // 更新项目（Late）
  void LateUpdate(float delta_time);

  // 处理碰撞
  void ExecuteCollision();
  // 处理约束
  void SolveConstraints(float delta_time);

  // 设置是否使用碰撞
  void UseCollision(bool value) { use_collision_ = value; }
  // 设置范围Box
  void UseBox(bool value) { use_box_ = value; }

  // 设置重力，只有一个
  void SetGravity(IVec3 value);
  // 设置阻力系数
  void SetDrag(float value);
  // 设置摩擦力系数
  void SetFriction(float value);

  // 给这个世界增加力
  void AddForce(IVec3 value);
  // 给这个世界增加旋转力
  void AddTorque(IVec3 value);
  // 删除这个世界的力
  void RemoveForce(IVec3 value);
  // 删除这个世界的旋转力
  void RemoveTorque(IVec3 value);

  // 将一个项目限制在Box里面
  void KeepInBox(RigidBody* r) const;
  // 设置Box的大小，此项目会直接使UseBox=True
  void SetWorldBox(IVec3 min, IVec3 max);

  // 加入一个RigidBody到世界，进行碰撞检查等
  void Add(RigidBody* rigid_body);

  // 增加一个Joint约束
  void AddJoint(RigidBody* a, RigidBody* b, IVec3 anchor);

  // 增加一个约束
  void AddConstraint(Constraint* constraint);
  // 得到约束
  eastl::vector<Constraint*>& GetConstraints() { return constraints_; }

public:
  ikit::sstr name;

private:
  void GetShapeBounds(const Collider& shape, IVec box_min, IVec box_max,
      IVec& out_valid_min, IVec& out_valid_max) const;

  Scene& scene_;
  eastl::vector<Constraint*> constraints_;
  eastl::vector<PenetrationConstraint> penetrations_;
  eastl::vector<RigidBody*> objects_;
  eastl::vector<IVec3> forces_;
  eastl::vector<IVec3> torques_;
  float drag_;
  float friction_;
  IVec3 gravity_;
  bool use_collision_;
  bool use_box_;
  IVec box_min_;
  IVec box_max_;
  // 是使用约束解决Penetration还是使用直接解决
  bool use_peneration_constration_;
};

} // namespace ifire::game